package com.example.core;

import com.example.annotation.AutoTable;
import com.example.config.AutoTableProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.annotation.Order;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.config.BeanDefinition;

import java.util.Set;

/**
 * 自动建表执行器
 * 在应用启动时自动扫描实体类并创建表
 */
@Slf4j
@Component
@Order(1)
public class AutoTableCreator implements CommandLineRunner {

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private AutoTableProperties autoTableProperties;

    @Autowired
    private TableParser tableParser;

    @Autowired
    private SqlGenerator sqlGenerator;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private TableComparator tableComparator;

    @Override
    public void run(String... args) throws Exception {
        if (!autoTableProperties.getEnabled()) {
            log.info("自动建表功能已禁用");
            return;
        }

        log.info("========================================");
        log.info("开始自动建表，模式: {}", autoTableProperties.getMode());
        log.info("========================================");

        // 扫描所有带 @AutoTable 注解的类
        String[] beanNames = applicationContext.getBeanNamesForType(Object.class);
        int tableCount = 0;

        for (String beanName : beanNames) {
            try {
                Class<?> beanClass = applicationContext.getType(beanName);
                if (beanClass != null && beanClass.isAnnotationPresent(AutoTable.class)) {
                    AutoTable autoTable = beanClass.getAnnotation(AutoTable.class);
                    if (autoTable.enable()) {
                        createTable(beanClass);
                        tableCount++;
                    }
                }
            } catch (Exception e) {
                log.error("处理bean异常: {}", beanName, e);
            }
        }

        // 也扫描包路径下的实体类
        int entityTableCount = scanEntityPackage();
        tableCount += entityTableCount;

        log.info("========================================");
        log.info("自动建表完成，共处理 {} 张表", tableCount);
        log.info("========================================");
    }

    /**
     * 扫描实体包
     * @return 创建的表数量
     */
    private int scanEntityPackage() {
        int count = 0;
        String[] entityPackages = autoTableProperties.getEntityPackages();
        
        if (entityPackages == null || entityPackages.length == 0) {
            log.debug("未配置实体包路径(entity-packages)，跳过包扫描");
            return count;
        }
        
        // 创建类路径扫描器
        ClassPathScanningCandidateComponentProvider scanner = 
            new ClassPathScanningCandidateComponentProvider(false);
        // 添加过滤器：只扫描带有 @AutoTable 注解的类
        scanner.addIncludeFilter(new AnnotationTypeFilter(AutoTable.class));
        
        try {
            for (String basePackage : entityPackages) {
                if (basePackage == null || basePackage.trim().isEmpty()) {
                    continue;
                }
                
                log.debug("扫描实体包: {}", basePackage);
                Set<BeanDefinition> beanDefinitions = scanner.findCandidateComponents(basePackage);
                
                for (BeanDefinition beanDefinition : beanDefinitions) {
                    try {
                        String className = beanDefinition.getBeanClassName();
                        Class<?> entityClass = Class.forName(className);
                        
                        if (entityClass.isAnnotationPresent(AutoTable.class)) {
                            AutoTable autoTable = entityClass.getAnnotation(AutoTable.class);
                            if (autoTable.enable()) {
                                createTable(entityClass);
                                count++;
                            } else {
                                log.debug("实体类 {} 的 @AutoTable.enable=false，跳过", entityClass.getSimpleName());
                            }
                        }
                    } catch (ClassNotFoundException e) {
                        log.warn("加载实体类失败: {}", beanDefinition.getBeanClassName(), e);
                    }
                }
            }
        } catch (Exception e) {
            log.error("扫描实体包失败", e);
        }
        
        return count;
    }

    /**
     * 创建表
     */
    private void createTable(Class<?> entityClass) {
        try {
            // 解析表结构
            TableInfo tableInfo = tableParser.parse(entityClass);
            String tableName = tableInfo.getTableName();

            log.info("处理表: {}", tableName);

            // 根据模式处理
            if ("create".equalsIgnoreCase(autoTableProperties.getMode())) {
                // 删除重建模式
                dropTable(tableName);
                executeCreateTable(tableInfo);
            } else if ("update".equalsIgnoreCase(autoTableProperties.getMode())) {
                // 更新模式：如果表不存在则创建，存在则同步表结构
                if (!isTableExists(tableName)) {
                    executeCreateTable(tableInfo);
                } else {
                    log.info("表 {} 已存在", tableName);
                    // 动态同步表结构
                    if (autoTableProperties.getDynamicSync()) {
                        syncTableStructure(tableInfo);
                    }
                }
            }

        } catch (Exception e) {
            log.error("创建表失败: {}", entityClass.getSimpleName(), e);
        }
    }

    /**
     * 执行建表
     */
    private void executeCreateTable(TableInfo tableInfo) {
        try {
            // 生成并执行建表SQL
            String createTableSql = sqlGenerator.generateCreateTableSql(tableInfo);

            if (autoTableProperties.getShowSql()) {
                log.info("执行SQL:\n{}", createTableSql);
            }

            jdbcTemplate.execute(createTableSql);
            log.info("表 {} 创建成功", tableInfo.getTableName());

            // 创建索引
            for (TableInfo.IndexInfo indexInfo : tableInfo.getIndexes()) {
                // 检查索引是否已存在
                if (!isIndexExists(tableInfo.getTableName(), indexInfo.getIndexName())) {
                    String createIndexSql = sqlGenerator.generateCreateIndexSql(
                            tableInfo.getTableName(), indexInfo);

                    if (autoTableProperties.getShowSql()) {
                        log.info("执行SQL:\n{}", createIndexSql);
                    }

                    jdbcTemplate.execute(createIndexSql);
                    log.info("索引 {} 创建成功", indexInfo.getIndexName());
                } else {
                    log.info("索引 {} 已存在，跳过创建", indexInfo.getIndexName());
                }
            }

        } catch (Exception e) {
            log.error("执行建表SQL失败", e);
            throw new RuntimeException("建表失败", e);
        }
    }

    /**
     * 删除表
     */
    private void dropTable(String tableName) {
        try {
            String dropSql = sqlGenerator.generateDropTableSql(tableName);

            if (autoTableProperties.getShowSql()) {
                log.info("执行SQL:\n{}", dropSql);
            }

            jdbcTemplate.execute(dropSql);
            log.info("表 {} 已删除", tableName);
        } catch (Exception e) {
            log.warn("删除表失败: {}", tableName, e);
        }
    }

    /**
     * 检查表是否存在
     */
    private boolean isTableExists(String tableName) {
        try {
            // MySQL数据库检查表是否存在
            String sql = "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE UPPER(TABLE_NAME) = UPPER(?)";
            Integer count = jdbcTemplate.queryForObject(sql, Integer.class, tableName);
            return count != null && count > 0;
        } catch (Exception e) {
            log.warn("检查表是否存在失败: {}", tableName, e);
            return false;
        }
    }
    
    /**
     * 检查索引是否存在
     */
    private boolean isIndexExists(String tableName, String indexName) {
        try {
            String sql = sqlGenerator.generateCheckIndexExistsSql(tableName, indexName);
            Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
            return count != null && count > 0;
        } catch (Exception e) {
            log.warn("检查索引是否存在失败: {}.{}", tableName, indexName, e);
            return false;
        }
    }

    /**
     * 同步表结构（动态添加/删除/修改字段）
     */
    private void syncTableStructure(TableInfo tableInfo) {
        try {
            String tableName = tableInfo.getTableName();
            log.info("开始同步表结构: {}", tableName);

            // 对比表结构差异
            TableComparator.TableDiff diff = tableComparator.compareTable(tableName, tableInfo);

            if (!diff.hasChanges()) {
                log.info("表 {} 结构无变化", tableName);
                return;
            }

            int changeCount = 0;

            // 1. 添加新字段
            if (!diff.getColumnsToAdd().isEmpty()) {
                log.info("检测到 {} 个新字段需要添加", diff.getColumnsToAdd().size());
                for (TableInfo.ColumnInfo column : diff.getColumnsToAdd()) {
                    String addColumnSql = sqlGenerator.generateAddColumnSql(tableName, column);

                    if (autoTableProperties.getShowSql()) {
                        log.info("执行SQL:\n{}", addColumnSql);
                    }

                    try {
                        jdbcTemplate.execute(addColumnSql);
                        log.info("✓ 添加字段成功: {}.{}", tableName, column.getColumnName());
                        changeCount++;
                    } catch (Exception e) {
                        log.error("✗ 添加字段失败: {}.{} - {}", tableName, column.getColumnName(), e.getMessage());
                    }
                }
            }

            // 2. 删除多余字段（需要配置允许）
            if (!diff.getColumnsToDrop().isEmpty()) {
                if (autoTableProperties.getAutoDropColumn()) {
                    log.warn("检测到 {} 个多余字段需要删除", diff.getColumnsToDrop().size());
                    for (String columnName : diff.getColumnsToDrop()) {
                        String dropColumnSql = sqlGenerator.generateDropColumnSql(tableName, columnName);

                        if (autoTableProperties.getShowSql()) {
                            log.info("执行SQL:\n{}", dropColumnSql);
                        }

                        try {
                            jdbcTemplate.execute(dropColumnSql);
                            log.warn("✓ 删除字段成功: {}.{}", tableName, columnName);
                            changeCount++;
                        } catch (Exception e) {
                            log.error("✗ 删除字段失败: {}.{} - {}", tableName, columnName, e.getMessage());
                        }
                    }
                } else {
                    log.warn("检测到 {} 个多余字段，但自动删除功能未开启（auto-drop-column=false）",
                            diff.getColumnsToDrop().size());
                    log.warn("多余字段列表: {}", diff.getColumnsToDrop());
                }
            }

            // 3. 修改字段类型（需要配置允许）
            if (!diff.getColumnsToModify().isEmpty()) {
                if (autoTableProperties.getAutoModifyColumn()) {
                    log.info("检测到 {} 个字段需要修改", diff.getColumnsToModify().size());
                    for (TableInfo.ColumnInfo column : diff.getColumnsToModify()) {
                        // 主键字段的特殊处理：只有在修复 AUTO_INCREMENT 时才允许修改
                        if (column.getPrimaryKey() != null && column.getPrimaryKey()) {
                            if (column.getAutoIncrement() != null && column.getAutoIncrement()) {
                                log.warn("检测到主键字段 {}.{} 缺少 AUTO_INCREMENT 属性，正在修复...", tableName, column.getColumnName());
                                // 允许继续执行修复
                            } else {
                                log.warn("跳过主键字段的修改: {}.{}", tableName, column.getColumnName());
                                continue;
                            }
                        }
                        
                        // 先处理 unique 索引的删除（如果需要）
                        if (!column.getUnique()) {
                            // 尝试删除可能存在的 unique 索引（uk_ 前缀）
                            String uniqueIndexName = "uk_" + tableName + "_" + column.getColumnName();
                            if (isIndexExists(tableName, uniqueIndexName)) {
                                try {
                                    String dropIndexSql = "ALTER TABLE `" + tableName + "` DROP INDEX `" + uniqueIndexName + "`;";
                                    if (autoTableProperties.getShowSql()) {
                                        log.info("执行SQL:\n{}", dropIndexSql);
                                    }
                                    jdbcTemplate.execute(dropIndexSql);
                                    log.info("✓ 删除 unique 索引成功: {}", uniqueIndexName);
                                } catch (Exception e) {
                                    log.warn("删除索引失败: {} - {}", uniqueIndexName, e.getMessage());
                                }
                            }
                            
                            // 也尝试删除普通索引（idx_ 前缀），以防万一
                            String normalIndexName = "idx_" + tableName + "_" + column.getColumnName();
                            if (isIndexExists(tableName, normalIndexName)) {
                                try {
                                    String dropIndexSql = "ALTER TABLE `" + tableName + "` DROP INDEX `" + normalIndexName + "`;";
                                    if (autoTableProperties.getShowSql()) {
                                        log.info("执行SQL:\n{}", dropIndexSql);
                                    }
                                    jdbcTemplate.execute(dropIndexSql);
                                    log.info("✓ 删除普通索引成功: {}", normalIndexName);
                                } catch (Exception e) {
                                    log.warn("删除索引失败: {} - {}", normalIndexName, e.getMessage());
                                }
                            }
                        }
                        
                        String modifyColumnSql = sqlGenerator.generateModifyColumnSql(tableName, column);

                        if (autoTableProperties.getShowSql()) {
                            log.info("执行SQL:\n{}", modifyColumnSql);
                        }

                        try {
                            jdbcTemplate.execute(modifyColumnSql);
                            log.info("✓ 修改字段成功: {}.{}", tableName, column.getColumnName());
                            changeCount++;
                            
                            // 添加 unique 索引（如果需要）
                            if (column.getUnique()) {
                                String indexName = "uk_" + tableName + "_" + column.getColumnName();
                                if (!isIndexExists(tableName, indexName)) {
                                    try {
                                        String createIndexSql = "ALTER TABLE `" + tableName + "` ADD UNIQUE INDEX `" + 
                                                              indexName + "` (`" + column.getColumnName() + "`);";
                                        if (autoTableProperties.getShowSql()) {
                                            log.info("执行SQL:\n{}", createIndexSql);
                                        }
                                        jdbcTemplate.execute(createIndexSql);
                                        log.info("✓ 添加 unique 索引成功: {}", indexName);
                                    } catch (Exception e) {
                                        log.error("添加 unique 索引失败: {} - {}", indexName, e.getMessage());
                                    }
                                }
                            }
                        } catch (Exception e) {
                            log.error("✗ 修改字段失败: {}.{} - {}", tableName, column.getColumnName(), e.getMessage());
                        }
                    }
                } else {
                    log.info("检测到 {} 个字段类型变化，但自动修改功能未开启（auto-modify-column=false）",
                            diff.getColumnsToModify().size());
                }
            }

            if (changeCount > 0) {
                log.info("表 {} 结构同步完成，共执行 {} 个变更", tableName, changeCount);
            }

        } catch (Exception e) {
            log.error("同步表结构失败: {}", tableInfo.getTableName(), e);
        }
    }
}
